同步 & 非同步(4) - async & await


Posted by TempuraEngineer on 2022-07-09

目錄


async & await

async、await是generator + Promise的語法糖。因為不必再使用Promise chaining,更加提升非同步函式的可讀性

async

  • 帶有async 關鍵字的function非await的部分事實上還是同步

    async function bar(){
      console.log('bar');
    }
    
    function foo(){
      console.log('foo');
    }
    
    bar();
    foo();
    
    // bar
    // foo
    
  • 不管是否使用await,async function內的動作都會返回一個Promise物件

    function wait(ms){
      return new Promise(r => {
        setTimeout(r, ms);
      })
    }
    
    async function foo(){
      return 'foo'; // [[Prototype]]: Promise
                    // [[PromiseState]]: "fulfilled"
                    // [[PromiseResult]]: "foo"
    }
    
    async function bar(){
      await wait(500);
      return 'bar'; // [[Prototype]]: Promise
                    // [[PromiseState]]: "fulfilled"
                    // [[PromiseResult]]: "bar"
    }
    


await

  • await 關鍵字可以讓執行暫停,直到Promise被完成

    The await keyword is for making the JavaScript function execution wait until a promise is settled

    async function bar(){
      console.log('bar');
    
      // 執行到await就暫停,先去執行同步函式foo
      await fetch('https://api.github.com/orgs/tailwindcss')
      .then((d) => d.json())
      .then(d => {
        console.log(d);
      })
    
      console.log('barr');
    }
    
    function foo(){
      console.log('foo');
    }
    
    bar();
    foo();
    
    // bar
    // foo
    // {login: 'tailwindcss', id: 30317862, node_id: 'MDEyOk9yZ2FuaXphdGlvbjMwMzE3ODYy', url: 'https://api.github.com/orgs/tailwindcss', repos_url: 'https://api.github.com/orgs/tailwindcss/repos', …}
    // barr
    
  • 只能放在async function裡

    function foo(){
      await fetch('https://api.github.com/orgs/bootstrapvue')
      .then(d => d.json())
      .then(d => console.log(d))
    }
    
    // VM1289:2 Uncaught SyntaxError: await is only valid in async functions and the top level bodies of modules
    
  • 迴圈執行非同步函式

    用迴圈執行非同步函式,且想要迴圈完成後再執行下一個指令時,可能會想這樣寫,但這樣會先執行console.log('done')(因為是同步)

      const urlArray = ['https://api.github.com/orgs/bootstrapvue', 'https://api.github.com/orgs/tailwindcss'];
    
      async function foo(arr){
        arr.forEach(async i => {
          await fetch(i)
          .then(d => d.json())
          .then(d => console.log(d))
        })
    
        console.log('done');
      }
    
      foo(urlArray);
    
      // done
      // {login: 'tailwindcss', id: 30317862, node_id: 'MDEyOk9yZ2FuaXphdGlvbjMwMzE3ODYy', url: 'https://api.github.com/orgs/tailwindcss', repos_url: 'https://api.github.com/orgs/tailwindcss/repos', …}
      // {login: 'nodejs', id: 9950313, node_id: 'MDEyOk9yZ2FuaXphdGlvbjk5NTAzMTM=', url: 'https://api.github.com/orgs/nodejs', repos_url: 'https://api.github.com/orgs/nodejs/repos', …}
    

    使用for await...of可以達到類似同步迭代的效果,但一樣只能用於async function裡

    The for await...of statement creates a loop iterating over async iterable objects as well as on sync iterables, including: built-in String, Array, Array-like objects (e.g., arguments or NodeList), TypedArray, Map, Set, and user-defined async/sync iterables.

    It invokes a custom iteration hook with statements to be executed for the value of each distinct property of the object. This statement can only be used inside an async function.

    const urlArray = ['https://api.github.com/orgs/bootstrapvue', 'https://api.github.com/orgs/tailwindcss'];
    
    async function foo(arr){
      for await(let i of arr){
        await fetch(i)
        .then(d => d.json())
        .then(d => console.log(d))
      }
    
      console.log('done');
    }
    
    foo(urlArray);
    
    // {login: 'tailwindcss', id: 30317862, node_id: 'MDEyOk9yZ2FuaXphdGlvbjMwMzE3ODYy', url: 'https://api.github.com/orgs/tailwindcss', repos_url: 'https://api.github.com/orgs/tailwindcss/repos', …}
    // {login: 'nodejs', id: 9950313, node_id: 'MDEyOk9yZ2FuaXphdGlvbjk5NTAzMTM=', url: 'https://api.github.com/orgs/nodejs', repos_url: 'https://api.github.com/orgs/nodejs/repos', …}
    // done
    
  • serial operation & parallel operation

      function foo(packageName){
        return fetch(`https://api.github.com/orgs/${packageName}`)
        .then(d => {
          console.log(`${packageName} done.`)
          return d.json();
        })
      }
    
      // 依序
      async function series() {
        return [await foo('vuejs'), await foo('nodejs'), await foo('tailwindcss')];
      }     
    
      // 平行
      async function parallel() {
        const vueInfo = foo('vuejs');
        const tailwindInfo = foo('tailwindcss');
        const nodeInfo = foo('nodejs'); // 先把Promise建立起來
    
        return [await vueInfo, await tailwindInfo, await nodeInfo];
      }    
    
      await series();
      await parallel();
    


🖊名詞解釋

名詞 解釋 其他
settled Promise已被完成,狀態不會再改變了


📖參考資料

async functions - make promise friendly
JavaScript async and await - in plain English, please

現代化的 JavaScript 併發 - Async Functions

MDN - for await...of

阮一峰 - async
阮一峰 - await


#Async #Await







Related Posts

一起來讀 CRAM - A Cognitive Robot Abstract Machine for Everyday Manipulation in Human Environments

一起來讀 CRAM - A Cognitive Robot Abstract Machine for Everyday Manipulation in Human Environments

Deep Learning on 3D object detection paper 閱讀路徑

Deep Learning on 3D object detection paper 閱讀路徑

什麼是 Pure Function?在 React 當中的重要性是什麼?

什麼是 Pure Function?在 React 當中的重要性是什麼?


Comments